package com.dimples.dd.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.nacos.shaded.com.google.common.annotations.VisibleForTesting;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dimples.dd.common.enums.CommonStatusEnum;
import com.dimples.dd.common.model.Option;
import com.dimples.dd.common.pojo.PageResult;
import com.dimples.dd.system.convert.DictConverter;
import com.dimples.dd.system.mapper.SystemDictDataMapper;
import com.dimples.dd.system.model.entity.SystemDictDataDO;
import com.dimples.dd.system.model.entity.SystemDictTypeDO;
import com.dimples.dd.system.model.form.DictForm;
import com.dimples.dd.system.model.query.DictPageQuery;
import com.dimples.dd.system.model.vo.DictDataSimpleRespVO;
import com.dimples.dd.system.model.vo.DictPageVO;
import com.dimples.dd.system.service.SystemDictDataService;
import com.dimples.dd.system.service.SystemDictTypeService;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.dimples.dd.common.exception.BizExceptionUtil.exception;
import static com.dimples.dd.common.exception.ErrorCode.*;

@Service
@RequiredArgsConstructor
public class SystemDictDataServiceImpl extends ServiceImpl<SystemDictDataMapper, SystemDictDataDO> implements SystemDictDataService {

    private final DictConverter dictConverter;
    @Resource
    @Lazy
    private SystemDictTypeService systemTypeService;

    /**
     * 排序 dictType > sort
     */
    private static final Comparator<SystemDictDataDO> COMPARATOR_TYPE_AND_SORT = Comparator
            .comparing(SystemDictDataDO::getDictType)
            .thenComparingInt(SystemDictDataDO::getSort);

    @Override
    public PageResult<DictPageVO> selectDictPage(DictPageQuery queryParams) {
        PageResult<SystemDictDataDO> dictDataPage = this.baseMapper.selectPage(queryParams);
        return this.dictConverter.entity2Page(dictDataPage);
    }

    @Override
    public DictForm selectDictForm(Long id) {
        // 获取entity
        SystemDictDataDO entity = this.getById(id);

        // 实体转换
        return dictConverter.entity2Form(entity);
    }

    @Override
    public List<DictDataSimpleRespVO> selectDictDataList(Integer status, String dictType) {
        List<DictDataSimpleRespVO> simpleRespVoList = CollUtil.newArrayList();
        // 获取所有的字典类型
        List<SystemDictTypeDO> dictTypeList = this.systemTypeService.selectListByStatus(CommonStatusEnum.ENABLE.getValue());
        List<SystemDictDataDO> dictDataList = this.baseMapper.selectListByStatusAndDictType(status, dictType);
        Map<String, List<SystemDictDataDO>> dictTypeMap = dictDataList.stream().collect(Collectors.groupingBy(SystemDictDataDO::getDictType));

        for (SystemDictTypeDO typeDO : dictTypeList) {
            DictDataSimpleRespVO simpleRespVO = new DictDataSimpleRespVO();
            simpleRespVO.setName(typeDO.getName());
            simpleRespVO.setDictCode(typeDO.getType());
            simpleRespVO.setDictDataList(this.dictConverter.entity2DataList(dictTypeMap.get(typeDO.getType())));
            simpleRespVoList.add(simpleRespVO);
        }
        return simpleRespVoList;
    }

    @Override
    public boolean createDict(DictForm dictForm) {
        // 校验字典类型有效
        validateDictTypeExists(dictForm.getDictType());
        // 校验字典数据的值的唯一性
        validateDictDataValueUnique(null, dictForm.getDictType(), dictForm.getValue());

        // 插入字典类型
        SystemDictDataDO dictData = dictConverter.form2Entity(dictForm);
        int insert = this.baseMapper.insert(dictData);
        return insert > 0;
    }

    @Override
    public boolean updateDict(Long id, DictForm dictForm) {
        // 校验自己存在
        validateDictDataExists(dictForm.getId());
        // 校验字典类型有效
        validateDictTypeExists(dictForm.getDictType());
        // 校验字典数据的值的唯一性
        validateDictDataValueUnique(dictForm.getId(), dictForm.getDictType(), dictForm.getValue());

        // 更新字典类型
        SystemDictDataDO updateObj = dictConverter.form2Entity(dictForm);
        int update = this.baseMapper.updateById(updateObj);
        return update > 0;
    }

    @VisibleForTesting
    public void validateDictDataValueUnique(Long id, String dictType, String value) {
        SystemDictDataDO dictData = this.baseMapper.selectByDictTypeAndValue(dictType, value);
        if (dictData == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的字典数据
        if (id == null) {
            throw exception(DICT_DATA_VALUE_DUPLICATE);
        }
        if (!dictData.getId().equals(id)) {
            throw exception(DICT_DATA_VALUE_DUPLICATE);
        }
    }

    @VisibleForTesting
    public void validateDictDataExists(Long id) {
        if (id == null) {
            return;
        }
        SystemDictDataDO dictData = this.baseMapper.selectById(id);
        if (dictData == null) {
            throw exception(DICT_DATA_NOT_EXISTS);
        }
    }

    @VisibleForTesting
    public void validateDictTypeExists(String type) {
        SystemDictTypeDO dictType = this.systemTypeService.selectDictType(type);
        if (dictType == null) {
            throw exception(DICT_TYPE_NOT_EXISTS);
        }
        if (ObjUtil.notEqual(dictType.getStatus().intValue(), CommonStatusEnum.ENABLE.getValue())) {
            throw exception(DICT_TYPE_NOT_ENABLE);
        }
    }

    @Override
    public boolean deleteDict(String idsStr) {
        List<Long> ids = Arrays.stream(StrUtil.splitToLong(idsStr, StrUtil.COMMA)).boxed().toList();

        // 删除字典数据
        int batchIds = this.baseMapper.deleteBatchIds(ids);
        return batchIds > 0;
    }

    @Override
    public List<Option<String>> listDictOptions(String typeCode) {
        // 数据字典项
        List<SystemDictDataDO> dictList = this.list(new LambdaQueryWrapper<SystemDictDataDO>()
                .select(SystemDictDataDO::getValue, SystemDictDataDO::getLabel)
                .eq(SystemDictDataDO::getDictType, typeCode)
        );

        // 转换下拉数据
        return CollectionUtil.emptyIfNull(dictList)
                .stream()
                .map(dictItem -> new Option<>(dictItem.getValue(), dictItem.getLabel()))
                .collect(Collectors.toList());
    }

    @Override
    public List<String> selectDictTypeByTypeCode(List<String> typeCodeList) {
        return this.baseMapper.selectDictTypeByTypeCode(typeCodeList);
    }
}
